package org.budo.cmbc.direct.sdk.impl;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.budo.cmbc.direct.sdk.entity.AbstractCmbcDirectRequest;
import org.budo.support.lang.util.FileUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.spring.io.util.ResourceUtil;
import org.springframework.core.io.Resource;

import com.cmbc.connect.DBankHttpsMessageSender;
import com.cmbc.connect.DBankMessageSender;
import com.cmbc.connect.IMesseageSender;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@ToString
@Getter
@Setter
@Slf4j
public abstract class AbstractCmbcDirectBankSdk {
    private String url;

    private String merchantNo;

    private String userPrivateFilePassword;

    private String privateKeyPath;

    private String publicKeyPath;

    /**
     * 20191217 luhl新增
     */
    private String trustJksPath;

    /**
     * 20191217 luhl新增
     */
    private String clientJksPath;

    /**
     * 20191217 luhl新增
     */
    private String jksFilePassword;

    private Resource privateKey;

    private Resource publicKey;

    /**
     * 20191217 luhl新增
     */
    private Resource clientJksKey;

    /**
     * 20191217 luhl新增
     */
    private Resource trustJksKey;

    public String clientJksPath() {
        if (FileUtil.exists(this.clientJksPath)) {
            return this.clientJksPath;
        }

        String resourceUrlFile = ResourceUtil.getURLFile(this.getClientJksKey());
        if (FileUtil.exists(resourceUrlFile)) {
            return resourceUrlFile;
        }

        log.warn("#77 clientJksPath=" + this.clientJksPath + ", clientJksKey=" + this.clientJksKey + ", this=" + this);
        return null;
    }

    public String trustJksPath() {
        if (null != this.trustJksPath && FileUtil.exists(this.trustJksPath)) {
            return this.trustJksPath;
        }

        String resourceUrlFile = ResourceUtil.getURLFile(this.getTrustJksKey());
        if (FileUtil.exists(resourceUrlFile)) {
            return resourceUrlFile;
        }

        log.warn("#91 trustJksPath=" + this.trustJksPath + ", trustJksKey=" + this.trustJksKey + ", this=" + this);
        return null;
    }

    public String publicKeyPath0() {
        if (FileUtil.exists(this.publicKeyPath)) {
            return this.publicKeyPath;
        }

        String resourceUrlFile = ResourceUtil.getURLFile(this.getPublicKey());
        if (FileUtil.exists(resourceUrlFile)) {
            return resourceUrlFile;
        }

        throw new IllegalArgumentException("#35 publicKeyPath=" + this.publicKeyPath + ", publicKey=" + this.publicKey + ", this=" + this);
    }

    public String privateKeyPath() {
        if (FileUtil.exists(this.privateKeyPath)) {
            return this.privateKeyPath;
        }

        String resourceUrlFile = ResourceUtil.getURLFile(this.getPrivateKey());
        if (FileUtil.exists(resourceUrlFile)) {
            return resourceUrlFile;
        }

        throw new IllegalArgumentException("#43 privateKeyPath=" + this.privateKeyPath + ", privateKey=" + this.privateKey + ", this=" + this);
    }

    protected IMesseageSender messeageSender() {
        try {
            return this.messeageSender_0();
        } catch (Throwable e) {
            log.error("#122 messeageSender_0, error=" + e + ", this=" + this, e);

            throw e instanceof RuntimeException //
                    ? (RuntimeException) e //
                    : new RuntimeException("#126 e=" + e, e);
        }
    }

    private IMesseageSender messeageSender_0() {
        // 根据jks文件是否存在使用不同的sender
        if (!StringUtil.isBlank(this.clientJksPath()) & !StringUtil.isBlank(this.trustJksPath())) {
            return new DBankHttpsMessageSender(this.privateKeyPath(), //
                    this.getUserPrivateFilePassword(), //
                    this.publicKeyPath0(), //
                    this.getUrl(), //
                    this.getMerchantNo(), //
                    this.clientJksPath(), //
                    this.trustJksPath(), //
                    this.getJksFilePassword(), //
                    this.getJksFilePassword());
        }

        return new DBankMessageSender(this.privateKeyPath(), //
                this.getUserPrivateFilePassword(), //
                this.publicKeyPath0(), //
                this.getUrl(), //
                this.getMerchantNo());
    }

    protected String channelJnlNo(AbstractCmbcDirectRequest request) {
        log.info("#158 setEProtocolAcNoAndChannelJnlNo, request=" + request);
        return request.getChannelJnlNo();
    }

    protected Map<String, Object> fieldValueMap(AbstractCmbcDirectRequest request, String[] fields) {
        int initialCapacity = 1 << (fields.length / 2);
        Map<String, Object> dataMap = new HashMap<>(initialCapacity);
        for (String each : fields) {
            Object fieldValue = this.getFieldValue(request, each);
            dataMap.put(each, fieldValue);
        }
        return dataMap;
    }

    protected Map<String, Object> setPwdResultFields(AbstractCmbcDirectRequest request, Map<String, Object> dataMap) {
        String[] methodNames = { "PwdResult", "RandJnlNo", "Random" };
        for (String name : methodNames) {
            dataMap.put(name, this.getFieldValue(request, name));
        }
        return dataMap;
    }

    protected Map<String, Object> setOldChangePwdResultFields(AbstractCmbcDirectRequest request, Map<String, Object> dataMap) {
        String[] methodNames = { "OldPwdResult", "OldRandJnlNo", "OldRandom" };
        for (String name : methodNames) {
            dataMap.put(name, this.getFieldValue(request, name));
        }
        return dataMap;
    }

    protected Map<String, Object> setNewChangePwdResultFields(AbstractCmbcDirectRequest request, Map<String, Object> dataMap) {
        String[] methodNames = { "NewPwdResult", "NewRandJnlNo", "NewRandom", "NewPwdResultConfirm" };
        for (String name : methodNames) {
            Object fieldValue = this.getFieldValue(request, name);
            dataMap.put(name, fieldValue);
        }
        return dataMap;
    }

    protected Map<String, Object> setSMSInfoFields(AbstractCmbcDirectRequest request, Map<String, Object> dataMap) {
        String[] methodNames = { "MessageTaskId", "MessageCode" };
        for (String name : methodNames) {
            dataMap.put(name, this.getFieldValue(request, name));
        }

        return dataMap;
    }

    protected Map<String, Object> setNewSMSInfoFields(AbstractCmbcDirectRequest request, Map<String, Object> dataMap) {
        String[] methodNames = { "NewMessageTaskId", "NewMobilePhone", "NewMessageCode" };

        for (String name : methodNames) {
            dataMap.put(name, this.getFieldValue(request, name));
        }

        return dataMap;
    }

    protected Map<String, Object> setThreeIdPictureFields(AbstractCmbcDirectRequest request, Map<String, Object> dataMap) {
        String[] methodNames = { "PhotoFront", "PhotoBack", "PhotoHold" };

        for (String name : methodNames) {
            dataMap.put(name, this.getFieldValue(request, name));
        }

        return dataMap;
    }

    protected String setEProtocolAcNoAndChannelJnlNo(AbstractCmbcDirectRequest request, Map<String, Object> dataMap) {
        // 查询时可能涉及到的
        // 电子账户协议号，开户后几乎所有操作均需要此参数
        Object fieldValue = this.getFieldValue(request, "EProtocolAcNo");
        dataMap.put("EProtocolAcNo", fieldValue);

        log.info("#574 setEProtocolAcNoAndChannelJnlNo, request=" + request);
        return request.getChannelJnlNo();
    }

    private Object getFieldValue(AbstractCmbcDirectRequest request, String fieldName) {
        try {
            Method method = request.getClass().getDeclaredMethod("get" + fieldName);
            method.setAccessible(true);
            return method.invoke(request);
        } catch (Throwable e) {
            log.warn("#588 getFieldValue, request=" + request + ", fieldName=" + fieldName + ", e=" + e);
            return null;
        }
    }
}
